
///////////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2009, Perry L Miller IV and Adam Kubach
//  All rights reserved.
//  BSD License: http://www.opensource.org/licenses/bsd-license.html
//
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
//
//  Base class for documents that read and write a file.
//
///////////////////////////////////////////////////////////////////////////////

#include "Usul/Documents/FileDocument.h"
#include "Usul/Atomic/Integer.h"
#include "Usul/Functions/NoThrow.h"
#include "Usul/Strings/Format.h"

#include "boost/bind.hpp"

using namespace Usul::Documents;

USUL_IMPLEMENT_IUNKNOWN_MEMBERS ( FileDocument, BaseClass );


///////////////////////////////////////////////////////////////////////////////
//
//  Returns the given name if it's valid or "Untitled 0", "Untitled 1", etc.
//
///////////////////////////////////////////////////////////////////////////////

namespace Helper
{
  typedef Usul::Atomic::Integer < unsigned long > Counter;
  Counter untitledCounter ( 0 );
  FileDocument::FileInfo getValidName ( const std::string &file )
  {
    if ( false == file.empty() )
      return FileDocument::FileInfo ( file, true );

    ++untitledCounter;
    const Counter::ValueType value ( untitledCounter );
    const std::string name ( Usul::Strings::format ( "Untitled ", value ) );
    return FileDocument::FileInfo ( name, false );
  }
}


///////////////////////////////////////////////////////////////////////////////
//
//  Constructor
//
///////////////////////////////////////////////////////////////////////////////

FileDocument::FileDocument ( const std::string &file ) : BaseClass(),
  _fileName ( Helper::getValidName ( file ) )
{
}


///////////////////////////////////////////////////////////////////////////////
//
//  Destructor
//
///////////////////////////////////////////////////////////////////////////////

FileDocument::~FileDocument()
{
  Usul::Functions::noThrow ( boost::bind ( &FileDocument::_destroy, this ), "1593739299" );
}


///////////////////////////////////////////////////////////////////////////////
//
//  Destroy this instance.
//
///////////////////////////////////////////////////////////////////////////////

void FileDocument::_destroy()
{
  _fileName = FileInfo ( std::string ( "Destroyed" ), false );
}


///////////////////////////////////////////////////////////////////////////////
//
//  Query the interfaces
//
///////////////////////////////////////////////////////////////////////////////

Usul::Interfaces::IUnknown *FileDocument::queryInterface ( unsigned long iid )
{
  switch ( iid )
  {
  case Usul::Interfaces::IFileDocument::IID:
    return static_cast < Usul::Interfaces::IFileDocument * > ( this );
  case Usul::Interfaces::IRead::IID:
    return static_cast < Usul::Interfaces::IRead * > ( this );
  default:
    return BaseClass::queryInterface ( iid );
  }
}


///////////////////////////////////////////////////////////////////////////////
//
//  Destroy this instance.
//
///////////////////////////////////////////////////////////////////////////////

void FileDocument::destroyObject()
{
  this->_destroy();
  BaseClass::destroyObject();
}


///////////////////////////////////////////////////////////////////////////////
//
//  Return a string suitable for a GUI window's title bar.
//
///////////////////////////////////////////////////////////////////////////////

std::string FileDocument::title() const
{
  FileName::Guard guard ( _fileName.mutex() );
  return _fileName.getReference().first;
}


///////////////////////////////////////////////////////////////////////////////
//
//  Return this document.
//
///////////////////////////////////////////////////////////////////////////////

const FileDocument *FileDocument::fileDocument() const
{
  return this;
}


///////////////////////////////////////////////////////////////////////////////
//
//  Return this document.
//
///////////////////////////////////////////////////////////////////////////////

FileDocument *FileDocument::fileDocument()
{
  return this;
}


///////////////////////////////////////////////////////////////////////////////
//
//  Set the file name.
//
///////////////////////////////////////////////////////////////////////////////

void FileDocument::fileName ( FileInfo &name )
{
  _fileName = name;
}


///////////////////////////////////////////////////////////////////////////////
//
//  Get the file name.
//
///////////////////////////////////////////////////////////////////////////////

FileDocument::FileInfo FileDocument::fileName() const
{
  return _fileName;
}


///////////////////////////////////////////////////////////////////////////////
//
//  Is the current file name valid?
//
///////////////////////////////////////////////////////////////////////////////

bool FileDocument::isFileNameValid() const
{
  const FileInfo info ( _fileName );
  return info.second;
}


///////////////////////////////////////////////////////////////////////////////
//
//  Read the file and add it to existing content. 
//  Overload for document-specific behavior.
//
///////////////////////////////////////////////////////////////////////////////

void FileDocument::read ( const std::string &, IUnknown::RefPtr )
{
}


///////////////////////////////////////////////////////////////////////////////
//
//  Write the document to given file name. Does not rename this document.
//  Overload for document-specific behavior.
//
///////////////////////////////////////////////////////////////////////////////

void FileDocument::write ( const std::string &, IUnknown::RefPtr )
{
}
